home *** CD-ROM | disk | FTP | other *** search
/ Aminet 24 / Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso / Aminet / comm / misc / CapiRexxVoiceM.lha / am.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-13  |  20.9 KB  |  1,045 lines

  1. /*
  2. **
  3. **    $Id: am.c,v 1.2 1995/10/07 02:52:18 chris Exp $
  4. **    $Revision: 1.2 $
  5. **
  6. **    $Filename: developer/am.c $
  7. **    $Author: chris $
  8. **    $Date: 1995/10/07 02:52:18 $ 
  9. **    $Portability: ANSI $
  10. **
  11. **    Ein kleiner Anrufbeantworter, setzt auf CAPI 2.0 auf.
  12. **
  13. **    THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF RELOG AG.
  14. **
  15. **    COPYRIGHT (C) 1992-1996 BY RELOG AG, ZUERICH. ALL RIGHTS RESERVED.
  16. **    NO PART OF THIS SOFTWARE MAY BE COPIED, REPRODUCED, OR TRANSMITTED
  17. **    IN ANY FORM OR BY ANY MEANS,  WITHOUT THE PRIOR WRITTEN PERMISSION
  18. **    OF RELOG AG.
  19. **
  20. */
  21.  
  22. #include <exec/types.h>
  23. #include <proto/exec.h>
  24. #include <dos/dos.h>
  25.  
  26. #include <stdio.h>
  27. #include <string.h>
  28.  
  29. #include "os.h"
  30. #include "alaw.h"
  31. #include "capi-usr.h"
  32.  
  33. #define  _AM
  34. #include "am.h"
  35. #include "arexx.h"
  36. #include "bchanneljobs.h"
  37. #include "process.h"
  38.  
  39.  
  40. static struct AnsweringMachine    am =
  41. {
  42.     1,                        /* Controller */
  43.     "8",                    /* MSN */
  44.     "limmathotline.amrx",    /* REXX-Script */
  45. };
  46.  
  47.  
  48. /*
  49. **    Locals
  50. */
  51. static U16    applID;
  52. static U32    capiproc;
  53. static BOOL    running = TRUE;
  54.  
  55.  
  56. /****************************************************************************
  57. **    Klein- nach Grossbuchstaben wandeln. $$$ Kann keine Umlaute
  58. */
  59.  
  60. static U8 ToUpper( U8 c )
  61. {
  62.     return (U8)(((c >= 'a') && (c <= 'z')) ? c + 'A' - 'a' : c);
  63. }
  64.  
  65.  
  66. /****************************************************************************
  67. **    Send a CAPI message to the CAPI driver
  68. */
  69.  
  70. U32
  71. SendCAPIMessage( CAPI_MESSAGE *msg, U8 *end )
  72. {
  73.     msg->TotalLength = end - (U8 *)msg;
  74.     return U_CAPI_PUT_MESSAGE( applID, msg );
  75. }
  76.  
  77.  
  78. /****************************************************************************
  79. **    Aus einem Array von CAPI-`struct's einen Zeiger auf die <num>te
  80. **    struct (d.h. auf das Längenbyte) zurückgeben
  81. */
  82.  
  83. static U8 *GetStruct( U8 *ptr, int num )
  84. {
  85.     while (num > 0)
  86.     {
  87.         if (*ptr == 0xFF)
  88.             ptr += (GET_U16(ptr+1) + 3);
  89.         else
  90.             ptr += *ptr + 1;
  91.  
  92.         num--;
  93.     }
  94.  
  95.     return ptr;
  96. }
  97.  
  98.  
  99. /****************************************************************************
  100. **    Add a null-terminated string as a struct to a CAPI message
  101. */
  102.  
  103. static VOID AddStructString( U8 **paraptr, U8 *string )
  104. {
  105.     U8    *para = *paraptr;
  106.     int    len = strlen( string );
  107.  
  108.     if (len < 0xFF)
  109.     {
  110.         ADD_PARA( para, U8, len );
  111.     }
  112.     else
  113.     {
  114.         ADD_PARA( para, U8, 0xFF );    /* Escape-Zeichen für 16Bit-Länge */
  115.         ADD_PARA( para, U16, len );
  116.     }
  117.  
  118.     strcpy( para, string );
  119.  
  120.     *paraptr = para + len;
  121. }
  122.  
  123.  
  124. /****************************************************************************
  125. **    Testen, ob eine MSN auf ein am-Entity passt. `msn' ist dabei ein
  126. **    CAPI struct, mit Längenbyte im ersten Byte.
  127. */
  128.  
  129. static BOOL CheckMSN( struct AnsweringMachine *am, U8 *ist )
  130. {
  131.     if (ToUpper( am->MSN[0] ) != 'X')    /* `Alle MSNs akzeptieren' ? */
  132.     {
  133.         U8 *p1, *p2, len = (U8)strlen( am->MSN );
  134.  
  135.         /* Ende der Called Party Number im CAPI struct */
  136.         p1 = ist + ist[0] + 1;
  137.  
  138.         /* Ende der MSN in unserer Konfiguration */
  139.         p2 = am->MSN + len;
  140.  
  141.         /*
  142.         **    Es werden nur soviele Zeichen verglichen,
  143.         **    wie die kürzere der beiden Nummern enthält.
  144.         **    Dadurch kann der Benutzer beispielsweise
  145.         **    statt seiner EAZ die ganze Nummer eingeben,
  146.         **    und ein Anruf wird trotzdem richtig erkannt.
  147.         */
  148.         if (len > ist[0])
  149.             len = ist[0];
  150.  
  151.         while (len)
  152.         {
  153.             if (*--p1 != *--p2)
  154.                 return FALSE;    /* Falsche MSN */
  155.             len--;
  156.         }
  157.     }
  158.  
  159.     return TRUE;    /* Nummer stimmt überein */
  160. }
  161.  
  162.  
  163. /****************************************************************************
  164. **    Ein Zeichen aus dem Keybuffer lesen und zurückgeben
  165. */
  166.  
  167. static U8 GetKey( struct AnsweringMachine *am )
  168. {
  169.     USES_DISABLE
  170.     U8 key = '-';        /* "-" heisst "keine Taste gedrückt" */
  171.  
  172.     DISABLE;
  173.     if (am->KeyBufferSize > 0)
  174.     {
  175.         key = am->KeyBuffer[0];
  176.         memmove( am->KeyBuffer, am->KeyBuffer+1, am->KeyBufferSize );
  177.         am->KeyBufferSize--;
  178.     }
  179.     ENABLE;
  180.  
  181.     return key;
  182. }
  183.  
  184.  
  185. /****************************************************************************
  186. **    Alle Zeichen aus dem Keybuffer entfernen
  187. */
  188.  
  189. static VOID FlushKeyBuffer( struct AnsweringMachine *am )
  190. {
  191.     am->KeyBufferSize = 0;
  192. }
  193.  
  194.  
  195. /****************************************************************************
  196. **    Auf ein Zeichen einer Auswahl warten. Falls keys ein leerer Strig
  197. **    ist, wartet die Funktion auf eine beliebige Taste. Falls keys das
  198. **    Zeichen '-' enthält, kehrt diese Funktion zurück, sobald ein SIGF_
  199. **    SINGLE empfangen wurde, sonst wartet sie.
  200. **    timeout ist in Sekunden. 0 = kein Timeout.
  201. */
  202.  
  203. static U8 WaitKeys( struct AnsweringMachine *am, U8 *keys, S32 timeout )
  204. {
  205.     S32 doomsday;
  206.  
  207.     for (doomsday = 0;; doomsday++)
  208.     {
  209.         U32    signals = CheckSignal( SIGBREAKF_CTRL_C | SIGF_SINGLE );
  210.         U8    key;
  211.  
  212.         if (timeout != 0)
  213.         {
  214.             if (doomsday >= (timeout * 4))
  215.             {
  216.                 printf( "WaitKeys(): timeout reached.\n" );
  217.                 return '-';
  218.             }
  219.         }
  220.  
  221.         if (signals & SIGBREAKF_CTRL_C)
  222.             return '-';        /* $$$ Macht das Sinn ? */
  223.  
  224.         if (signals & SIGF_SINGLE)
  225.             if (strchr( keys, '-' ))
  226.                 return '-';
  227.  
  228.         if ((key = GetKey( am )) != '-')
  229.         {
  230.             if ((keys[0] == '\0') || (strchr( keys, key ) != NULL))
  231.                 return key;
  232.         }
  233.         else Delay( TICKS_PER_SECOND / 4 );
  234.     }
  235. }
  236.  
  237.  
  238. /****************************************************************************
  239. **    REXX-Kommando: Background <file> <volume> [LOOP]
  240. */
  241.  
  242. S32 RXFunc_Background( char *args, struct AnsweringMachine *am )
  243. {
  244.     char filename[PATHNAMESIZE];
  245.  
  246.     if (ARexx_GetString( &args, filename, sizeof( filename ) ))
  247.     {
  248.         S32 volume;
  249.  
  250.         if (ARexx_GetInteger( &args, &volume ))
  251.         {
  252.             char    loop[16];
  253.             U16        jobflags = JOBF_WRITE | JOBF_AUTOFREE;
  254.  
  255.             loop[0] = '\0';
  256.             if (ARexx_GetString( &args, loop, sizeof( loop ) ))
  257.             {
  258.                 if (!stricmp( loop, "LOOP" ))
  259.                     jobflags |= JOBF_LOOP;
  260.             }
  261.  
  262.             printf( "Background: file='%s', volume=%ld, loop='%s'\n", filename, volume, loop );
  263.  
  264.             if (volume > 100)
  265.                 volume = 100;
  266.             if (volume < 0)
  267.                 volume = 0;
  268.  
  269.             volume = (volume * B_VOLUME_MAX) / 100;
  270.  
  271.             if (am->BGJob != NULL)
  272.             {
  273.                 BChannel_FreeJob( am->BGJob );
  274. /*                am->BGJob = NULL; */
  275.             }
  276.  
  277.             if (am->BGJob = BChannel_AddJob( am->BChannel, filename, jobflags, (U16)volume, am->Process ))
  278.                 return RC_OK;
  279.  
  280.             return RC_WARN;
  281.         }
  282.     }
  283.  
  284.     return RC_FATAL;
  285. }
  286.  
  287.  
  288. /****************************************************************************
  289. **    REXX-Kommando: Fade <endvolume>
  290. */
  291.  
  292. S32 RXFunc_Fade( char *args, struct AnsweringMachine *am )
  293. {
  294.     S32 volume;
  295.  
  296.     if (ARexx_GetInteger( &args, &volume ))
  297.     {
  298.         BOOL waiting = TRUE;
  299.         USES_DISABLE
  300.  
  301.         printf( "Fade: volume=%ld\n", volume );
  302.  
  303.         if (volume > 100)
  304.             volume = 100;
  305.         if (volume < 0)
  306.             volume = 0;
  307.  
  308.         volume = (volume * B_VOLUME_MAX) / 100;
  309.  
  310.         DISABLE;
  311.         if (am->BGJob != NULL)
  312.             am->BGJob->EndVolume = (U16)volume;
  313.         ENABLE;
  314.  
  315.         while (waiting)
  316.         {
  317.             DISABLE;
  318.             if (am->BGJob != NULL)
  319.             {
  320.                 if (am->BGJob->ActVolume == am->BGJob->EndVolume)
  321.                     waiting = FALSE;
  322.             }
  323.             else
  324.             {
  325.                 waiting = FALSE;
  326.             }
  327.             ENABLE;
  328.             Delay( TICKS_PER_SECOND );
  329.         }
  330.  
  331.         return RC_OK;
  332.     }
  333.     return RC_FATAL;
  334. }
  335.  
  336.  
  337. /****************************************************************************
  338. **    REXX-Kommando: Hangup [cause]
  339. */
  340.  
  341. S32 RXFunc_HangUp( char *args, struct AnsweringMachine *am )
  342. {
  343.     struct
  344.     {
  345.         CAPI_MESSAGE    Msg;
  346.         U8                Para[8];
  347.     } disconnect_b3_req;
  348.  
  349.     U8 *para = disconnect_b3_req.Para;
  350.  
  351.     S32 cause = 16;        /* NORMAL CALL CLEARING */
  352.  
  353.     ARexx_GetInteger( &args, &cause );
  354.  
  355.     FlushKeyBuffer( am );
  356.     printf( "Hangup: cause=%ld\n", cause );
  357.  
  358.     disconnect_b3_req.Msg.Command        = CAPICMD_DISCONNECT_B3;
  359.     disconnect_b3_req.Msg.Subcommand    = CAPISUBCMD_REQ;
  360.  
  361.     ADD_PARA( para, U32, am->NCCI );        /* NCCI des aktuellen Calls */
  362.     ADD_PARA( para, U8, 0 );                /* NCPI brauchen wir nicht */
  363.  
  364.     SendCAPIMessage( &disconnect_b3_req.Msg, para );
  365.  
  366.     return RC_OK;
  367. }
  368.  
  369.  
  370. /****************************************************************************
  371. **    REXX-Kommando: Play <file> <volume> [keys]
  372. */
  373.  
  374. S32 RXFunc_Play( char *args, struct AnsweringMachine *am )
  375. {
  376.     char filename[PATHNAMESIZE];
  377.  
  378.     if (ARexx_GetString( &args, filename, sizeof( filename ) ))
  379.     {
  380.         S32 volume;
  381.  
  382.         if (ARexx_GetInteger( &args, &volume ))
  383.         {
  384.             struct BChannel_Job    *job;
  385.             char                keys[20];
  386.  
  387.             keys[0] = '\0';
  388.             if (ARexx_GetString( &args, keys, sizeof( keys ) ))
  389.             {
  390.             }
  391.  
  392.             printf( "Play: file='%s', volume=%ld, keys='%s'\n", filename, volume, keys );
  393.  
  394.             if (volume > 100)
  395.                 volume = 100;
  396.             if (volume < 0)
  397.                 volume = 0;
  398.  
  399.             volume = (volume * B_VOLUME_MAX) / 100;
  400.  
  401.             FlushKeyBuffer( am );
  402.             if (job = BChannel_AddJob( am->BChannel, filename, JOBF_WRITE, (U16)volume, am->Process ))
  403.             {
  404.                 rexx_resultstring[0] = WaitKeys( am, keys, 0 );
  405.                 rexx_resultstring[1] = '\0';
  406.  
  407.                 BChannel_FreeJob( job );
  408.                 return RC_OK;
  409.             }
  410.  
  411.             return RC_WARN;
  412.         }
  413.     }
  414.  
  415.     return RC_FATAL;
  416. }
  417.  
  418.  
  419. /****************************************************************************
  420. **    REXX-Kommando: Record <file> <maxtime> [keys]
  421. */
  422.  
  423. S32 RXFunc_Record( char *args, struct AnsweringMachine *am )
  424. {
  425.     char filename[PATHNAMESIZE];
  426.  
  427.     if (ARexx_GetString( &args, filename, sizeof( filename ) ))
  428.     {
  429.         S32 maxtime;
  430.  
  431.         if (ARexx_GetInteger( &args, &maxtime ))
  432.         {
  433.             struct BChannel_Job    *job;
  434.             char                keys[20];
  435.  
  436.             keys[0] = '\0';
  437.             if (ARexx_GetString( &args, keys, sizeof( keys ) ))
  438.             {
  439.             }
  440.  
  441.             printf( "Record: file='%s', maxtime=%ld, keys='%s'\n", filename, maxtime, keys );
  442.  
  443.             FlushKeyBuffer( am );
  444.             if (job = BChannel_AddJob( am->BChannel, filename, JOBF_READ, B_VOLUME_MAX, am->Process ))
  445.             {
  446.                 rexx_resultstring[0] = WaitKeys( am, keys, maxtime );
  447.                 rexx_resultstring[1] = '\0';
  448.  
  449.                 BChannel_FreeJob( job );
  450.                 return RC_OK;
  451.             }
  452.  
  453.             return RC_WARN;
  454.         }
  455.     }
  456.  
  457.     return RC_FATAL;
  458. }
  459.  
  460.  
  461. /****************************************************************************
  462. **    REXX-Kommando: WaitKey
  463. */
  464.  
  465. S32 RXFunc_WaitKey( char *args, struct AnsweringMachine *am )
  466. {
  467.     printf( "WaitKey\n" );
  468.  
  469.     FlushKeyBuffer( am );
  470.  
  471.     rexx_resultstring[0] = WaitKeys( am, "", 0 );
  472.     rexx_resultstring[1] = '\0';
  473.  
  474.     return RC_OK;
  475. }
  476.  
  477.  
  478. /****************************************************************************
  479. **    LISTEN_REQ an CAPI abschicken
  480. */
  481.  
  482. static VOID ListenReq( U8 controller )
  483. {
  484.     struct
  485.     {
  486.         CAPI_MESSAGE    Msg;
  487.         U8                Para[32];                    /* $$$ Rough guess */
  488.     } listen_req;
  489.  
  490.     U8 *para = listen_req.Para;
  491.  
  492.     listen_req.Msg.Command        = CAPICMD_LISTEN;
  493.     listen_req.Msg.Subcommand    = CAPISUBCMD_REQ;
  494.  
  495.     ADD_PARA( para, U32, controller );                /* Controller */
  496.  
  497.     ADD_PARA( para, U32, 0xFFFFFFFF );                /* Info mask: alles */
  498.  
  499.     ADD_PARA( para, U32,                            /* CIP mask: Nur Gespräche */
  500.               (1UL << CAPI_CIP_SPEECH)
  501.             | (1UL << CAPI_CIP_AUDIO31)
  502.             | (1UL << CAPI_CIP_TELEPHONY) );
  503.  
  504.     ADD_PARA( para, U32, 0 );                        /* CIP mask 2: reserviert */
  505.     ADD_PARA( para, U8, 0 );                        /* Calling party number */
  506.     ADD_PARA( para, U8, 0 );                        /* Calling party subaddress */
  507.  
  508.     SendCAPIMessage( &listen_req.Msg, para );
  509. }
  510.  
  511.  
  512. /****************************************************************************
  513. **    Touchtone-Dekodierung einschalten (79)
  514. */
  515.  
  516. static VOID TouchtoneDecoder( U32 ncci, BOOL onoff )
  517. {
  518.     struct
  519.     {
  520.         CAPI_MESSAGE    Msg;
  521.         U8                Para[32];                    /* $$$ Rough guess */
  522.     } facility_req;
  523.  
  524.     U8 *para = facility_req.Para;
  525.  
  526.     facility_req.Msg.Command    = CAPICMD_FACILITY;
  527.     facility_req.Msg.Subcommand    = CAPISUBCMD_REQ;
  528.  
  529.     ADD_PARA( para, U32, ncci );
  530.     ADD_PARA( para, U16, 1 );                /* Facility Selector: DTMF */
  531.  
  532.     ADD_PARA( para, U8,    7 );                /* Struct length */
  533.     ADD_PARA( para, U16, onoff ? 1 : 2 );    /*  Function: Start/Stop DTMF listen */
  534.     ADD_PARA( para, U16, 40 );                /*  Time in ms for one digit (ignored) */
  535.     ADD_PARA( para, U16, 40 );                /*  Time in ms between digits (ignored) */
  536.     ADD_PARA( para, U8, 0 );                /*  Struct digits (ignored) */
  537.  
  538.     SendCAPIMessage( &facility_req.Msg, para );
  539. }
  540.  
  541.  
  542. /****************************************************************************
  543. **    Eine CAPI-Message behandeln
  544. */
  545.  
  546. static BOOL HandleCAPIMessage( struct AnsweringMachine *am, CAPI_MESSAGE *msg )
  547. {
  548.     UBYTE     *para = (UBYTE *)(msg+1);
  549.     BOOL    running = TRUE;
  550.  
  551.     switch (msg->Subcommand)
  552.     {
  553.         case CAPISUBCMD_CONF:
  554.             switch (msg->Command)
  555.             {
  556.                 /*
  557.                 **    DATA_B3_CONF (Seite 33)
  558.                 */
  559.                 case CAPICMD_DATA_B3:
  560.                 {
  561.                     U32 ncci;
  562.                     U16 handle;
  563.  
  564.                     GET_PARA( para, U32, ncci );
  565.                     GET_PARA( para, U16, handle );
  566.  
  567.                     BChannel_DataB3Conf( ncci );
  568.                 }
  569.                     break;
  570.  
  571.  
  572.                 /*
  573.                 **    LISTEN_CONF (Seite 54)
  574.                 */
  575.                 case CAPICMD_LISTEN:
  576.                 {
  577.                     U32 controller;
  578.                     U16 info;
  579.  
  580.                     GET_PARA( para, U32, controller );
  581.                     GET_PARA( para, U16, info );
  582.  
  583.                     if (info != CAPI_00_REQUEST_ACCEPTED)
  584.                     {
  585.                         printf( "LISTEN_REQ failed (error 0x%04x)\n", info );
  586.                         running = FALSE;
  587.                     }
  588.                 }
  589.                     break;
  590.  
  591.  
  592.                 /*
  593.                 **    FACILITY_CONF (Seite 45)
  594.                 */
  595.                 case CAPICMD_FACILITY:
  596.                 {
  597.                     U32 ncci;
  598.                     U16 info;
  599.  
  600.                     GET_PARA( para, U32, ncci );
  601.                     GET_PARA( para, U16, info );
  602.  
  603.                     if (info != CAPI_00_REQUEST_ACCEPTED)
  604.                     {
  605.                         printf( "FACILITY_REQ for ncci 0x%08lx failed (error 0x%04x)\n", ncci, info );
  606.                         running = FALSE;
  607.                     }
  608.                 }
  609.                     break;
  610.  
  611.  
  612.                 default:
  613.                     INTERNAL_ERROR;
  614.                     break;
  615.  
  616.             }
  617.             break;
  618.  
  619.  
  620.  
  621.  
  622.         case CAPISUBCMD_IND:
  623.             msg->Subcommand = CAPISUBCMD_RESP;        /* Für Antwort-Messages */
  624.  
  625.             switch (msg->Command)
  626.             {
  627.                 /*
  628.                 **    CONNECT_IND (Seite 19)
  629.                 */
  630.                 case CAPICMD_CONNECT:
  631.                 {
  632.                     U32    plci;
  633.                     U16    cip;
  634.                     U16    reject = CAPI_REJECT_IGNORE;
  635.  
  636.                     GET_PARA( para, U32, plci );
  637.                     GET_PARA( para, U16, cip );
  638.  
  639.                     if (CheckMSN( am,  GetStruct( para, 0 )))
  640.                     {
  641.                         if (am->PState == P0_IDLE)
  642.                         {
  643.                             U8 *str;
  644.  
  645.                             am->PLCI    = plci;
  646.                             am->PState    = P2_CONNECT_INDICATION;
  647.  
  648.  
  649.                             /*
  650.                             **    Calling Party Number übernehmen. Die ersten
  651.                             **    zwei Bytes der struct enthalten Type of Number
  652.                             **    und Presentation Indicator, und werden ignoriert.
  653.                             */
  654.                             str = GetStruct( para, 1 );
  655.                             if (str[0] >= 2)    /* Falls Nummer vorhanden */
  656.                             {
  657.                                 memcpy( am->CallingNumber, str + 1 + 2, str[0] - 2 );
  658.                                 am->CallingNumber[str[0] - 2] = '\0';
  659.                             }
  660.                             else
  661.                                 am->CallingNumber[0] = '\0';
  662.  
  663.                             printf( "Got a call from %s\n", am->CallingNumber );
  664.  
  665.                             reject = CAPI_REJECT_ACCEPT;
  666.                             am->PState = P4_CALL_ACCEPTED;
  667.                         }
  668.                     }
  669.  
  670.  
  671.                     /*
  672.                     **    Entsprechende CONNECT_RESP-Message vorbereiten
  673.                     */
  674.                     para = (U8 *)(msg+1) + 4;        /* PLCI übernehmen */
  675.                     ADD_PARA( para, U16, reject );
  676.  
  677.                     ADD_PARA( para, U8, 9 );                        /* B Protocol: Struct-Länge */
  678.                     ADD_PARA( para, U16, CAPI_B1PROT_TRANSP64 );    /* B1 protocol */
  679.                     ADD_PARA( para, U16, CAPI_B2PROT_TRANSP );        /* B2 protocol */
  680.                     ADD_PARA( para, U16, CAPI_B3PROT_TRANSP );        /* B3 protocol */
  681.                     ADD_PARA( para, U8, 0 );                        /* B1 configuration: leer */
  682.                     ADD_PARA( para, U8, 0 );                        /* B2 configuration: leer */
  683.                     ADD_PARA( para, U8, 0 );                        /* B3 configuration: leer */
  684.  
  685.                     ADD_PARA( para, U8, 0 );        /* Struct ConnectedNumber */
  686.                     ADD_PARA( para, U8, 0 );        /* Struct ConnectedSubaddress */
  687.                     ADD_PARA( para, U8, 0 );        /* Struct LLC */
  688.                     ADD_PARA( para, U8, 0 );        /* Struct AdditionalInfo */
  689.                 }
  690.                     break;
  691.  
  692.  
  693.                 /*
  694.                 **    CONNECT_ACTIVE_IND (Seite 22)
  695.                 */
  696.                 case CAPICMD_CONNECT_ACTIVE:
  697.                 {
  698.                     U32    plci;
  699.  
  700.                     GET_PARA( para, U32, plci );
  701.                     am->PState = P_ACTIVE;
  702.                 }
  703.                     break;
  704.  
  705.  
  706.                 /*
  707.                 **    CONNECT_B3_IND (Seite 28)
  708.                 */
  709.                 case CAPICMD_CONNECT_B3:
  710.                 {
  711.                     U32    ncci;
  712.  
  713.                     GET_PARA( para, U32, ncci );
  714. /*                    GET_PARA( para, U32, ncpi ); */
  715.  
  716.                     am->NCCI = ncci;
  717.  
  718.                     if ((am->BChannel = BChannel_New( ncci )) != NULL)
  719.                     {
  720.                     }
  721.  
  722.                     ADD_PARA( para, U16, CAPI_REJECT_ACCEPT );
  723.                     ADD_PARA( para, U8, 0);        /* Kein NCPI */
  724.  
  725.                 }
  726.                     break;
  727.  
  728.  
  729.                 /*
  730.                 **    CONNECT_B3_ACTIVE_IND (Seite 24)
  731.                 */
  732.                 case CAPICMD_CONNECT_B3_ACTIVE:
  733.                 {
  734.                     char buf[256];
  735.                     U32    ncci;
  736.  
  737.                     GET_PARA( para, U32, ncci );
  738.                     printf( "B-channel activated.\n" );
  739.  
  740.                     am->Process = Process_Create( NULL, am, "AM-REXX", 2 );
  741.                     Process_WakeUp( am->Process );
  742.  
  743.                     TouchtoneDecoder( ncci, TRUE );
  744.  
  745.  
  746.                     /*
  747.                     **    PARSE arg callednumber callingnumber
  748.                     */
  749.                     sprintf( buf, "limmathotline.amrx %s %s", "?", am->CallingNumber );
  750.  
  751.                     printf( "Launching Rexx: %s\n", buf );
  752.                     ARexx_LaunchScript( Process_GetRexxPort( am->Process ), buf );
  753.                 }
  754.                     break;
  755.  
  756.  
  757.                 /*
  758.                 **    DATA_B3_IND (Seite 34)
  759.                 */
  760.                 case CAPICMD_DATA_B3:
  761.                 {
  762.                     U32    ncci;
  763.                     U8    *data;
  764.                     U16    size, handle, flags;
  765.  
  766.                     GET_PARA( para, U32,  ncci );
  767.                     GET_PARA( para, U8 *, data );
  768.                     GET_PARA( para, U16,  size );
  769.                     GET_PARA( para, U16,  handle );
  770.                     GET_PARA( para, U16,  flags );
  771.  
  772.                     BChannel_DataB3Ind( ncci, data, size );
  773.  
  774.                     para = (U8 *)(msg+1) + 4;        /* Nach NCCI */
  775.                     ADD_PARA( para, U16, handle );
  776.                 }
  777.                     break;
  778.  
  779.  
  780.                 /*
  781.                 **    DISCONNECT_IND (Seite 42)
  782.                 */
  783.                 case CAPICMD_DISCONNECT:
  784.                 {
  785.                     U32    plci;
  786.                     U16    reason;
  787.  
  788.                     GET_PARA( para, U32, plci );
  789.                     GET_PARA( para, U16, reason );
  790.  
  791.                     if (am->BChannel != NULL)
  792.                     {
  793.                         BChannel_Free( am->BChannel );
  794.                         am->BChannel = NULL;
  795.                     }
  796.  
  797.                     am->NCCI        = 0;
  798.  
  799.                     am->PState        = P0_IDLE;
  800.                     am->PLCI        = 0;
  801.  
  802.                     Process_Delete( am->Process );
  803.  
  804.                     para = (U8 *)(msg+1) + 4;    /* DISCONNECT_RESP hat nur PLCI */
  805.                     printf( "Connection terminated.\n" );
  806.                 }
  807.                     break;
  808.  
  809.  
  810.                 /*
  811.                 **    DISCONNECT_B3_IND (Seite 38)
  812.                 */
  813.                 case CAPICMD_DISCONNECT_B3:
  814.                 {
  815.                     U32    ncci;
  816.                     U16    reason_b3;
  817.  
  818.                     GET_PARA( para, U32, ncci );
  819.                     GET_PARA( para, U16, reason_b3 );
  820.  
  821.                     am->NCCI = 0;
  822.  
  823.                     Process_Delete( am->Process );
  824.  
  825.                     if (am->BChannel != NULL)
  826.                     {
  827.                         BChannel_Free( am->BChannel );
  828.                         am->BChannel = NULL;
  829.                     }
  830.  
  831.                     para = (U8 *)(msg+1) + 4;    /* DISCONNECT_B3_RESP hat nur NCCI */
  832.                     printf( "B-channel deactivated.\n" );
  833.                 }
  834.                     break;
  835.  
  836.  
  837.                 /*
  838.                 **    FACILITY_IND
  839.                 */
  840.                 case CAPICMD_FACILITY:
  841.                 {
  842.                     U32    ncci;
  843.                     U16 type;
  844.  
  845.                     GET_PARA( para, U32, ncci );
  846.                     GET_PARA( para, U16, type );
  847.  
  848.                     switch (type)
  849.                     {
  850.                         case 1:        /* DTMF */
  851.                         {
  852.                             U8 numkeys, key;
  853.  
  854.                             GET_PARA( para, U8, numkeys );
  855.  
  856.                             while (numkeys)
  857.                             {
  858.                                 USES_DISABLE
  859.                                 char buf[PATHNAMESIZE];
  860.  
  861.                                 GET_PARA( para, U8, key );
  862.  
  863.                                 /*
  864.                                 **    Key an Keybuffer anhängen
  865.                                 */
  866.                                 DISABLE;
  867.                                 if (am->KeyBufferSize < sizeof( am->KeyBuffer ))
  868.                                 {
  869.                                     am->KeyBuffer[am->KeyBufferSize] = key;
  870.                                     am->KeyBufferSize++;
  871.                                 }
  872.                                 ENABLE;
  873.  
  874.                                 if ((key >= '0') && (key <= '9'))
  875.                                 {
  876.                                     sprintf( buf, "Ansagen/Keys/KEY-%lc", (U32)key );
  877.                                     BChannel_AddJob( am->BChannel, buf, JOBF_WRITE, B_VOLUME_MAX, 0 );
  878.                                 }
  879.                                 numkeys--;
  880.                             }
  881.                         }
  882.                             break;
  883.  
  884.                         default:
  885.                             printf( "Unknown facility %ld\n", (U32)type );
  886.                             break;
  887.                     }
  888.                 }
  889.                     break;
  890.  
  891.  
  892.                 /*
  893.                 **    INFO_IND
  894.                 */
  895.                 case CAPICMD_INFO:
  896.                 {
  897.                     U32    plci;
  898.                     U16    infonumber;
  899.                     U8    infosize;
  900.  
  901.                     GET_PARA( para, U32, plci );
  902.                     GET_PARA( para, U16, infonumber );
  903.                     GET_PARA( para, U8, infosize );        /* Grösse der Info-Struct */
  904.  
  905.                     para = (U8 *)(msg+1) + 4;    /* INFO_RESP: Nur PLCI */
  906.                 }
  907.                     break;
  908.  
  909.  
  910.                 default:
  911.                     INTERNAL_ERROR;
  912.                     break;
  913.             }
  914.  
  915.  
  916.             /*
  917.             **    Vorbereitete Message (normalerweise Antwortmessage auf _IND) senden.
  918.             **    Para zeigt hier auf das Ende der zu sendenden Message.
  919.             */
  920.             SendCAPIMessage( msg, para );
  921.             break;
  922.     }
  923.  
  924.     return running;
  925. }
  926.  
  927.  
  928. /****************************************************************************
  929. **    Diese Funktion wird vom CAPI-Treiber aufgerufen, wenn eine neue
  930. **    CAPI-Message bereitliegt. Sie weckt einfach unseren CAPI-Prozess.
  931. */
  932.  
  933. static void __saveds MySignalHandler( unsigned short applID, unsigned long para )
  934. {
  935.     Process_WakeUp( para );
  936. }
  937.  
  938.  
  939. /****************************************************************************
  940. **    Diese Funktion wird vom CAPI-Prozess aufgerufen, wenn er aufgeweckt
  941. **    wurde.
  942. */
  943.  
  944. static BOOL __saveds CAPIProcFunc( VOID *para )
  945. {
  946.     CAPI_MESSAGE *msg;
  947.  
  948.     while (U_CAPI_GET_MESSAGE( applID, &msg ) == 0)
  949.     {
  950.         running = HandleCAPIMessage( para, msg );
  951.     }
  952.  
  953.     return TRUE;
  954. }
  955.  
  956.  
  957. /****************************************************************************
  958. **    Das Hauptprogramm
  959. */
  960.  
  961. int main( int argc, char **argv )
  962. {
  963.     U16    error;
  964.  
  965.  
  966.     if (!((argc == 1) || ((argc == 2) && strcmp( argv[1], "?")) || (argc > 2)))
  967.     {
  968.         printf( "Usage: %s [number]\n", argv[0] );
  969.         return 10;
  970.     }
  971.  
  972.  
  973.     /*
  974.     **    Als erstes finden wir raus, ob in diesem Rechner überhaupt ein
  975.     **    CAPI-Treiber installiert ist.
  976.     */
  977.     if (U_CAPI_INSTALLED())
  978.     {
  979.         printf( "No CAPI driver installed!\n" );
  980.         return 10;
  981.     }
  982.  
  983.  
  984.     /*
  985.     **    CAPI initialisieren. Dies muss ganz am Anfang geschehen, bevor
  986.     **    irgendwelche CAPI-Funktionen (ausser U_CAPI_INSTALLED) aufgerufen
  987.     **    werden.
  988.     */
  989.     if ((error = U_CAPI_REGISTER( 2, 2, B_BLOCKSIZE, &applID )))
  990.     {
  991.         printf( "Can't initialize CAPI, error 0x%lx\n", error );
  992.         return 10;
  993.     }
  994.  
  995.     ARexx_Init();
  996.     ALAW_Init();
  997.  
  998.  
  999.     /*
  1000.     **    Infos über den CAPI-Treiber ausgeben
  1001.     */
  1002.     {
  1003.         U32    ver[4];
  1004.         U8    manu[64];
  1005.  
  1006.         U_CAPI_GET_VERSION( ver );
  1007.         U_CAPI_GET_MANUFACTURER( manu );
  1008.  
  1009.         printf( "Driver: %s\nVersion %ld.%ld (internal revision %ld.%ld)\n\n",
  1010.             manu, ver[0], ver[1], ver[2], ver[3] );
  1011.     }
  1012.  
  1013.  
  1014.     /*
  1015.     **    CAPI-Handler-Prozess und Callback-Funktion initialisieren.
  1016.     */
  1017.     if (capiproc = Process_Create( CAPIProcFunc, &am, "AM-CAPI", 15 ))
  1018.     {
  1019.         U_CAPI_SET_SIGNAL( applID, (ULONG)MySignalHandler, capiproc );
  1020.  
  1021.         ListenReq( am.Controller );
  1022.  
  1023.         Wait( SIGBREAKF_CTRL_C );
  1024.  
  1025.         Process_Delete( capiproc );
  1026.         capiproc = (U32)NULL;
  1027.     }
  1028.     else
  1029.     {
  1030.         printf( "Can't create CAPI handler process\n" );
  1031.     }
  1032.  
  1033.  
  1034.     ALAW_Exit();
  1035.     ARexx_Exit();
  1036.  
  1037.     /*
  1038.     **    CAPI schliessen.
  1039.     */
  1040.     U_CAPI_RELEASE( applID );
  1041.  
  1042.     return 0;
  1043. }
  1044.  
  1045.